package cc.wsyw126.java.collection.set;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 测试HashSet and LinkedHashSet
 * HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等，并且两个对象的hashCode()方法的返回值相等
 * LinkedHashSet集合也是根据元素的hashCode值来决定元素的存储位置，但和HashSet不同的是，它同时使用链表维护元素的次序，这样使得元素看起来是以插入的顺序保存的。
 * LinkedHashSet在迭 代访问Set中的全部元素时，性能比HashSet好，但是插入时性能稍微逊色于HashSet。
 * 其实当HashCode值一样，这个存储位置会采用链式结构保存两个HashCodeObj对象。
 * 用HashSet添加可变对象，要注意当对象有可能修改后和其他对象矛盾，这样我们无法从HashSet找到准确我们需要的对象。
 * Created by junpeng.yang on 16/8/25.
 */
public class TestSet {
    /**
     * 得到一个List<User>
     *
     * @param n
     * @return
     */
    public List<TestSet.User> getList(int n) {
        return Stream.generate(new TestSet.UserSupplier()).limit(n).collect(Collectors.toList());
    }

    /**
     * 得到一个List<Integer>
     *
     * @param n
     * @return
     */
    public List<Integer> getListInteger(int n) {
        return Stream.generate(() -> (int) (System.nanoTime() % 100)).limit(n).collect(Collectors.toList());
    }

    /**
     * 测试两者的插入的性能
     */
    public void testInsertTime() {
        System.out.println("-----------------------------------------------");
        System.out.println("TestSet.testInsertTime 测试两者的插入的性能");
        List<Integer> list = getListInteger(10000000);
        HashSet<Integer> hashSet = new HashSet<>();
        LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>();
        long start = System.currentTimeMillis();
        for (Integer integer : list) {
            linkedHashSet.add(integer);
        }
        System.out.println("linedHashSet执行插入操作的时间：" + (System.currentTimeMillis() - start));
        start = System.currentTimeMillis();
        for (Integer integer : list) {
            hashSet.add(integer);
        }
        System.out.println("HashSet执行插入操作的时间：" + (System.currentTimeMillis() - start));
        System.out.println("-----------------------------------------------");

    }

    /**
     * 测试linedhashset保持插入的顺序
     */
    public void testKeepOrder() {
        System.out.println("-----------------------------------------------");
        System.out.println("TestSet.testInsertTime 测试linedhashset保持插入的顺序");
        TestSet testSet = new TestSet();
        List<TestSet.User> list = testSet.getList(10);

        HashSet<TestSet.User> hashSet = new HashSet<>();
        LinkedHashSet<TestSet.User> linkedHashSet = new LinkedHashSet<>();

        for (TestSet.User u : list) {
            hashSet.add(u);
            linkedHashSet.add(u);
        }

        list.stream().forEach(n -> System.out.print(n.age + " "));
        System.out.println();
        hashSet.stream().forEach(n -> System.out.print(n.age + " "));
        System.out.println();
        linkedHashSet.stream().forEach(n -> System.out.print(n.age + " "));
        System.out.println();
        System.out.println("-----------------------------------------------");
    }

    public static void main(String[] args) {
        TestSet testSet = new TestSet();

        testSet.testKeepOrder();

        testSet.testInsertTime();
    }

    private class User {
        int age;
        String name;

        public User(int age, String name) {
            this.age = age;
            this.name = name;
        }
    }

    /**
     * 生产User对象的方法
     */
    private class UserSupplier implements Supplier<TestSet.User> {
        private Random random = new Random();

        @Override
        public User get() {
            int no = random.nextInt(100);
            return new TestSet.User(no, no + "" + random.nextInt(100));
        }
    }
}
